package com.niit.mall.user.controller;


import cn.hutool.core.bean.BeanUtil;
import com.aliyun.oss.ServiceException;
import com.niit.mall.common.api.CommonResult;
import com.niit.mall.common.domain.dto.PageDTO;
import com.niit.mall.common.utils.BeanUtils;
import com.niit.mall.user.domain.dto.*;
import com.niit.mall.user.domain.po.*;
import com.niit.mall.user.domain.query.RoleQuery;
import com.niit.mall.user.domain.vo.*;
import com.niit.mall.user.service.*;
import com.niit.mall.user.utils.AliyunOSSOperator;
import com.niit.mall.common.utils.UserContext;
import com.niit.mall.user.domain.query.UserQuery;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 用户服务
 * @module pardo_mall
 * @BelongsProject: pardo_mall_backend
 * @BelongsPackage: com.niit.mall.admin.controller
 * @Author: ChuXuan
 * @CreateTime: 2025-05-22  00:12
 * @Description: 用户控制器
 * @Version: 1.0
 */
@RestController
@RequestMapping("/users")
@Slf4j
@RequiredArgsConstructor
public class UserController {

	/**
	 * 使用 RequiredArgsConstructor 注解
	 * 会自动为 final 修饰的属性创建构造函数，并注入对应的依赖。
	 * 替代 @Autowired
	 */
	private final IUserService userService;

	private final PasswordEncoder passwordEncoder;

	private final IUserInfoService userInfoService;

	private final IUserOperateLogService userOperateLogService;

	private final IUserLoginLogService userLoginLogService;

	private final IRoleService roleService;

	private final AliyunOSSOperator aliyunOSSOperator;

	private final IUserRoleService userRoleService;

	private final IMenuService menuService;


	/**
	 * 用户登录接口
	 *
	 * @param loginDTO 用户登录信息数据传输对象
	 * @return 登录结果，包含用户登录视图对象
	 */
	@PostMapping("/login")
	public CommonResult<UserLoginVO> login(@RequestBody @Validated UserLoginDTO loginDTO) {
		UserLoginVO userLoginVO = userService.login(loginDTO);
		return CommonResult.success(userLoginVO,  "登录成功");
	}

	/**
	 * 检查用户名或手机号是否重复的方法
	 *
	 * @param keyword 用户名或手机号的字符串关键字
	 * @return 如果用户名或手机号已存在，返回验证失败结果；否则返回null
	 */
	@GetMapping("/check-repeat")
	public CommonResult checkUsername(@RequestParam String keyword) {
		log.info("检查用户名 | 手机号 是否已存在: {}", keyword);
		 if (userService.checkRepeat(keyword)) {
			return CommonResult.validateFailed("用户名已存在");
		}
		return null;

	}

	/**
	 * 用户注册接口
	 *
	 * @param userRegisterDTO 用户注册信息数据传输对象
	 * @return 通用结果对象，包含注册操作的结果信息
	 */
	@PostMapping("/register")
	public CommonResult register(@RequestBody @Validated UserRegisterDTO userRegisterDTO) {
		log.info("用户注册 {}", userRegisterDTO);
		return saveUser(userRegisterDTO);
	}


	/**
	 * 用户登出方法
	 * <p>
	 * 该方法用于处理用户登出请求。
	 *
	 * @return 返回登出操作的结果，通常为操作成功的通用响应对象
	 */
	@PutMapping("/logout")
	public CommonResult logout() {
		userService.logout();
		return CommonResult.success("登出");
	}

	/**
	 * 新增用户的方法。
	 * 接收用户信息数据传输对象，并将其保存到数据库。
	 *
	 * @param userRegisterDTO 用户注册信息数据传输对象
	 * @return 返回通用结果对象，包含操作成功标志和影响行数
	 */
	@PostMapping
	public CommonResult saveUser(@RequestBody UserRegisterDTO userRegisterDTO) {
		log.info("新增用户 {}",  userRegisterDTO);
		//DTO转PO
		User user = BeanUtil.copyProperties(userRegisterDTO, User.class);
		// 设置时间
		user.setCreateDate(LocalDate.now());
		user.setUpdateDate(LocalDate.now());
		// 加密密码
		String rawPassword = user.getPassword();
		String encodedPassword = passwordEncoder.encode(rawPassword);
		user.setPassword(encodedPassword);

		boolean flag = userService.save(user);
		// 初始化用户信息
		UserInfo userInfo = new UserInfo();
		userInfo.setUserId(user.getId());
		userInfo.setCreateDate(LocalDate.now());
		userInfo.setUpdateDate(LocalDate.now());
		userInfo.setProfilePicture("https://pardo-mall-bucket.oss-cn-shenzhen.aliyuncs.com/default.png");
		userInfoService.save(userInfo);

		// 初始化用户权限
		UserRoleDTO userRoleDTO = new UserRoleDTO( null, user.getId(), 10001L);

		// 设置用户权限
		updateRole(userRoleDTO);

		if  (flag) {
			return CommonResult.success(null);
		}else {
			return CommonResult.failed();
		}
	}

	/**
	 * 根据用户ID删除用户
	 *
	 * @param id 用户唯一标识
	 * @return 删除操作的结果，成功返回包含删除数量，失败返回失败信息
	 */
	@DeleteMapping("{id}")
	public CommonResult deleteUser(@PathVariable Long id) {

		Long userId = UserContext.getUser();
		UserOperateLog log = new UserOperateLog();
		log = log.updateLog(userId, id);
		userOperateLogService.save(log);

		boolean flag = userService.removeById(id);
		if  (flag) {
			return CommonResult.success(1);
		}else {
			return CommonResult.failed();
		}
	}

	/**
	 * 根据用户ID查询用户信息。
	 *
	 * @param id 用户唯一标识
	 * @return 封装用户信息的{@link CommonResult}对象
	 */
	@GetMapping("{id}")
	public CommonResult<UserVO> getUserById(@PathVariable Long id) {
		UserVO  uservo = userService.queryUserAndAddressById(id);
		return CommonResult.success(uservo);
	}

	@PutMapping("/reduceBalance")
	CommonResult<Void> reduceBalance(@RequestParam("totalPrice") Double totalPrice){
		Long userId = UserContext.getUser();
		// 根据用户id 减少余额
		UserInfo userInfo = userInfoService.getById(userId);
		if (userInfo.getBalance() < totalPrice) {
			throw new ServiceException("余额不足");
		}
		userInfo.setBalance((int) (userInfo.getBalance() - totalPrice));
		userInfoService.updateById(userInfo);
		return CommonResult.success(null);
	}
	/**
	 * 减少指定用户ID的余额
	 *
	 * @param id    用户ID
	 * @param money 减少的金额
	 * @return 执行结果
	 */
//	@PutMapping("/{id}/deduction/{money}")
//	public CommonResult deductionUserBalance(@PathVariable Long id, @PathVariable Integer money) {
//		String result = userService.deductionUserBalance(id, money);
//		return CommonResult.success(result);
//	}

	/**
	 * 根据查询条件分页获取用户列表
	 *
	 * @param query 用户查询条件
	 * @return 分页用户列表的封装结果
	 */
	@GetMapping("/page")
	public CommonResult<PageDTO<UserVO>> getUsersByPage(UserQuery query) {

		PageDTO<UserVO> page = userService.queryUserPage(query);

		// 根据用户id 和最新登录时间 查询UserLoginLog
		PageDTO<UserVO> newPage = userLoginLogService.addLoginLog(page);

		return CommonResult.success(newPage);
	}


	/**
	 * 更新用户信息接口
	 *
	 * @param userInfoDTO 用户信息数据传输对象
	 * @return 返回通用结果，成功时包含更新结果，失败时包含错误信息
	 */
	@PutMapping("/info")
	public CommonResult updateUserInfo(@RequestBody UserInfoDTO userInfoDTO) {
		Long  userId = UserContext.getUser();
		log.info("更新用户信息 {}", userInfoDTO);
		userService.updateUserInfo(userId,userInfoDTO);
		return  CommonResult.success(null);
	}

	/**
	 * 批量保存用户信息的方法
	 *
	 * @param userRegisterDTO 包含多个用户注册信息的DTO对象列表
	 * @return 返回包含操作成功标识的通用结果对象
	 */
	@PostMapping("/batch")
	public CommonResult batchSaveUser(@RequestBody List<UserRegisterDTO> userRegisterDTO) {

		// DTO 转换为 PO，并设置额外字段
		List<User> users = userRegisterDTO.stream()
				.map(dto -> {
					User user = BeanUtil.copyProperties(dto, User.class);
					user.setCreateDate(LocalDate.now());
					user.setUpdateDate(LocalDate.now());
					user.setPassword(passwordEncoder.encode(dto.getPassword())); // 加密密码
					return user;
				})
				.collect(Collectors.toList());
		boolean flag = userService.saveBatch(users);
		return CommonResult.success(flag);
	}

	/**
	 * 根据用户ID查询用户信息的方法
	 *
	 * @return 封装用户信息的通用结果对象
	 */
	@GetMapping("/info")
	public CommonResult<UserInfoVO> queryUserInfoById() {
		Long id = UserContext.getUser();
		UserInfoVO userInfoVO = userInfoService.queryUserInfoByUserId(id);
		return CommonResult.success(userInfoVO);
	}



	/**
	 * 上传文件至服务器。
	 *
	 * @param file 需要上传的文件
	 * @return 返回上传后的文件URL及操作结果
	 * @throws Exception 当文件上传过程中发生错误时抛出异常
	 */
	@PostMapping("/upload")
	public CommonResult<String> upload(@RequestParam("file") MultipartFile file) throws Exception {
		String url = aliyunOSSOperator.upload(file.getBytes(), Objects.requireNonNull(file.getOriginalFilename()));
		return CommonResult.success(url);
	}


	/**
	 * 查询用户类型信息的方法
	 *
	 * @return 返回包含角色信息的通用结果对象
	 */
	@GetMapping("/type")
	public CommonResult<RoleVO> queryUserType() {
		Long userId = UserContext.getUser();
		RoleVO roleVO = roleService.queryUserRoleByUserId(userId);
		return CommonResult.success(roleVO);
	}

	/**
	 * 根据用户id查询用户类型
	 * @param id 用户id
	 * @return 角色信息
	 */
	@GetMapping("/type/{id}")
	public CommonResult<RoleVO> queryUserType(@PathVariable("id") Long id) {
		RoleVO roleVO = roleService.queryUserRoleByUserId(id);
		return CommonResult.success(roleVO);
	}

	/**
	 * 更新用户信息
	 * @param userDTO 用户信息
	 */
	@PutMapping
	public CommonResult saveUser(@RequestBody UserDTO userDTO) {
		// 获取用户基础信息
		User user = BeanUtil.copyProperties(userDTO, User.class);
		// 更新用户基础信息
		userService.updateById(user);

		// 获取用户详细信息
		UserInfo userInfo = BeanUtil.copyProperties(userDTO.getUserInfo(), UserInfo.class);

		// 更新用户详细信息
		userInfoService.updateById(userInfo);
		return CommonResult.success(null);
	}

	/**
	 * 分页获取角色权限列表
	 * @param query 查询参数
	 * @return 权限分页列表
	 */
	@GetMapping("/role/page")
	public CommonResult<PageDTO<RoleVO>> queryUserRoleByPage(RoleQuery query) {
		PageDTO<RoleVO> pageDTO = roleService.queryUserRoleByPage(query);
		return CommonResult.success(pageDTO);
	}

	/**
	 * 获取全部角色权限列表
	 * @return 全部角色权限列表
	 */
	@GetMapping("/user_role")
	public CommonResult<List<RoleVO>> getAllRoles(){
		List<Role> roleList = roleService.list();
		List<RoleVO> roleVOList = BeanUtil.copyToList(roleList, RoleVO.class);
		return CommonResult.success(roleVOList);
	}

	/**
	 * 获取用户角色
	 * @param id 用户ID
	 * @return 用户角色
	 */
	@GetMapping("/user_role/{id}")
	public CommonResult<UserRoleVO> queryUserRole(@PathVariable Long id){
		UserRoleVO userRoleVO = BeanUtils.copyBean(userRoleService.queryUserRoleByUserId(id), UserRoleVO.class);
		return CommonResult.success(userRoleVO);
	}

	/**
	 * 更新角色权限
	 * @return 更新结果
	 */
	@PutMapping("/user_role")
	@Transactional(rollbackFor = Exception.class)
	public CommonResult updateRole(@RequestBody UserRoleDTO userRoleDTO) {
	    try {
	        // 参数校验
	        if (userRoleDTO == null || (userRoleDTO.getId() == null && userRoleDTO.getRoleId() == null)) {
	            return CommonResult.validateFailed("请求参数不能为空");
	        }

	        // 如果id为空，则添加角色权限
	        if (userRoleDTO.getId() == null) {
	            UserRole userRole = BeanUtils.copyBean(userRoleDTO, UserRole.class);
	            userRoleService.save(userRole);
				roleService.updateRoleNum(userRole.getRoleId(), 1);
	            return CommonResult.success("角色权限添加成功");
	        }

	        // 查询现有角色信息
	        UserRole existingRole = userRoleService.getById(userRoleDTO.getId());
	        if (existingRole == null) {
	            return CommonResult.failed("用户角色不存在，ID: " + userRoleDTO.getId());
	        }

	        Long oldRoleId = existingRole.getRoleId();
	        Long newRoleId = userRoleDTO.getRoleId();

	        // 参数校验
	        if (Objects.equals(oldRoleId, newRoleId)) {
	            return CommonResult.validateFailed("新旧角色ID相同，无需更新");
	        }

	        // 更新角色使用计数
	        roleService.updateRoleNum(oldRoleId, -1);
	        roleService.updateRoleNum(newRoleId, 1);

	        // 执行更新操作
	        UserRole userRole = BeanUtil.copyProperties(userRoleDTO, UserRole.class);
	        boolean result = userRoleService.updateById(userRole);
	        return result ? CommonResult.success("角色更新成功") : CommonResult.failed("角色更新失败");

	    } catch (IllegalArgumentException | ServiceException e) {
	        log.error("角色更新异常: {}", e.getMessage(), e);
	        return CommonResult.failed(e.getMessage());
	    } catch (NullPointerException e) {
	        log.error("空指针异常: 角色ID[{}]数据异常", userRoleDTO.getId(), e);
	        return CommonResult.failed("数据异常，请检查角色信息");
	    } catch (Exception e) {
	        log.error("未知异常: ", e);
	        return CommonResult.failed("系统异常，请联系管理员");
	    }
	}



	/**
	 * 更新角色权限
	 * @param roleDTO 角色权限
	 * @return 更新结果
	 */
	@PutMapping("/role")
	public CommonResult queryUserRole(@RequestBody RoleDTO roleDTO){
		Role role = BeanUtil.copyProperties(roleDTO, Role.class);
		role.setUpdateDate(LocalDate.now());
		boolean result = roleService.updateById(role);
		return result ? CommonResult.success("角色权限更新成功") : CommonResult.failed();
	}

	/**
	 * 根据id获取角色权限
	 * @param id 角色权限id
	 * @return 角色权限
	 */
	@GetMapping("/role/{id}")
	public CommonResult<RoleVO> queryRole(@PathVariable Long id){
		Role role = roleService.getById(id);
		RoleVO roleVO = BeanUtils.copyProperties(role, RoleVO.class);
		return CommonResult.success(roleVO);
	}

	/**
	 * 添加角色权限
	 * @param roleDTO 角色权限
	 * @return 添加结果
	 */
	@PostMapping("/role")
	public CommonResult addRole(@RequestBody RoleDTO roleDTO){
		Role role = BeanUtils.copyProperties(roleDTO, Role.class);
		role.setCreateDate(LocalDate.now());
		role.setUpdateDate(LocalDate.now());
		boolean save = roleService.save(role);
		return save ? CommonResult.success("角色添加成功") : CommonResult.success(false);
	}

	/**
	 * 删除角色权限
	 * @param id 角色id
	 * @return 删除结果
	 */
	@DeleteMapping("/role/{id}")
	public CommonResult deleteRole(@PathVariable Long id){
		boolean remove = roleService.removeById(id);
		return remove ? CommonResult.success("角色删除成功") : CommonResult.failed("角色删除失败");
	}

	/**
	 * 获取菜单列表
	 * @return 菜单列表
	 */
	@GetMapping("/menu/list")
	public CommonResult<List<MenuVO>> queryUserMenuList() {
		List<Menu> menuList = menuService.list();
		List<MenuVO> menuVOList = BeanUtil.copyToList(menuList, MenuVO.class);
		return CommonResult.success(menuVOList);
	}

	/**
	 * 根据id获取菜单信息
	 * @param id 菜单id
	 * @return 菜单信息
	 */
	@GetMapping("/menu/{id}")
	public CommonResult<MenuVO> queryUserMenu(@PathVariable Long id) {
		Menu menu = menuService.getById(id);
		MenuVO menuVO = BeanUtils.copyBean(menu, MenuVO.class);
		return CommonResult.success(menuVO);
	}

	/**
	 * 更新菜单信息
	 * @param menuDTO 菜单信息
	 * @return 更新结果
	 */
	@PutMapping("/menu")
	public CommonResult updateMenu(@RequestBody MenuDTO menuDTO) {
		Menu menu = BeanUtil.copyProperties(menuDTO, Menu.class);
		menu.setUpdateDate(LocalDate.now());
		boolean result = menuService.updateById(menu);
		return result ? CommonResult.success("菜单更新成功") : CommonResult.failed("菜单更新失败");
	}

	/**
	 * 添加菜单信息
	 * @param menuDTO 菜单信息
	 * @return 添加结果
	 */
	@PostMapping("/menu")
	public CommonResult addMenu(@RequestBody MenuDTO menuDTO) {
		Menu menu = BeanUtil.copyProperties(menuDTO, Menu.class);
		menu.setCreateDate(LocalDate.now());
		menu.setUpdateDate(LocalDate.now());
		boolean result = menuService.save(menu);
		return result ? CommonResult.success("菜单添加成功") : CommonResult.failed("菜单添加失败");
	}

	/**
	 * 删除菜单信息
	 * @param id 菜单id
	 * @return 删除结果
	 */
	@DeleteMapping("/menu/{id}")
	public CommonResult deleteMenu(@PathVariable Long id) {
		boolean result = menuService.removeById(id);
		return result ? CommonResult.success("菜单删除成功") : CommonResult.failed("菜单删除失败");
	}

	/**
	 * 根据角色id更改权限json
	 * @param roleDTO 角色信息
	 * @return 更新结果
	 */
	@PutMapping("/role/assignment")
	@Transactional
	public CommonResult updateRoleAssignment(@RequestBody RoleDTO roleDTO) {
		Role role = roleService.getById(roleDTO.getId());
		if (role == null) {
			return CommonResult.failed("角色不存在");
		}
		role.setAssignment(roleDTO.getAssignment());
		role.setUpdateDate(LocalDate.now());
		boolean result = roleService.updateById(role);
		return result ? CommonResult.success("权限更新成功") : CommonResult.failed("权限更新失败");
	}

	/**
	 * 根据角色id获取权限json
	 * @param id 角色id
	 * @return 权限json
	 */
	@GetMapping("/role/assignment/{id}")
	public CommonResult<Map<String, List<String>>> queryRoleAssignment(@PathVariable Long id) {
    	return CommonResult.success(roleService.queryAssignmentById(id));
	}



    // 清空用户搜索历史记录
//	@DeleteMapping("/search/history")
//	public CommonResult clearSearchHistory() {
//		Long userId = UserContext.getUser();
//		userSearchHistoryService.remove(Wrappers.<UserSearchHistory>lambdaQuery().eq(UserSearchHistory::getUserId, userId));
//		return CommonResult.success(null);
//	}

}
